package com.gitee.wsl.reflect

import kotlinx.atomicfu.locks.SynchronizedObject
import kotlinx.atomicfu.locks.synchronized
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty


// thanks to https://stackoverflow.com/a/47948047/9630725
class LazyMutable<T>(val initializer: () -> T, val rejectSetAfterGet: Boolean = false) : ReadWriteProperty<Any?, T>, SynchronizedObject() {
    private object UninitializedValue
    private var prop: Any? = UninitializedValue
    private var readAccessed = false

    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return if (prop == UninitializedValue) {
            synchronized(this) {
                readAccessed = true
                return if (prop == UninitializedValue) initializer().also { prop = it } else prop as T
            }
        } else {
            prop as T
        }
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        synchronized(this) {
            if (rejectSetAfterGet && readAccessed) {
                throw IllegalStateException("This lazy property doesn't allow set() after get()")
            }
            prop = value
        }
    }
}